#include "language.h"
#include "syntax_entry.h"
#include "parse_info.h"
#include <iostream>

using namespace std;

namespace syntax_analysis
{
	syntax_type syntax_entry::get_type()
	{
		return SYNTAX_ENTRY;
	}

	string syntax_entry::to_string()
	{
		string decl;
		decl += m_name;
		if( m_on_error_goto_syntax != "" )
		{
			decl += "<";
			decl += m_on_error_goto_syntax;
			decl += ">";
		}
		if( m_body != NULL )
		{
			decl += "=";
			decl += m_body->to_string();
		}
		decl += ";";
		return decl;
	}
	
	bool syntax_entry::reparse( parse_info *info )
	{
		parse_para *para;
		parse_info *child_info;
		bool result = false;

		para = info->get_parse_para();
		if( para == NULL )
			return false;

		if( info->get_child().size() != 1 ||
			para->get_acceptted_count() > 0 && para->get_acceptted_syn( para->get_acceptted_count()-1 ) != this )
			debug_info( info );
		
		inc_called();
		para->push_call( this );
		
		child_info = info->get_child( 0 );
		result = do_reparse( para, m_body, child_info );
		
		if( !result )
		{
			para->get_language()->set_error( para->get_callstack(), para->get_last_start_code() );
			para->pop_call();
		}
		else
		{
			para->pop_call();
		}
		
		return result;
	}

	bool syntax_entry::parse( parse_info *info )
	{
		parse_para *para;
		parse_info *child_info;
		bool result = false;

		para = info->get_parse_para();
		if( para == NULL )
			return false;

		inc_called();
		para->push_call( this );

		if( info->get_child().size() > 1 )
			debug_info( info );

		info->remove_child( 0 );
		child_info = info->create_child( para->get_last_start_code(), para->get_language() );

		result = do_parse( para, m_body, child_info );
		
		if( !result )
		{
			para->get_language()->set_error( para->get_callstack(), para->get_last_start_code() );
			para->pop_call();
		}
		else
		{
			para->pop_call();
		}
		
		return result;
	}

	bool syntax_entry::do_reparse( parse_para *para, syntax *syn, parse_info *child_info )
	{
		bool result = false;
		
		if( syn == this )
			syn->debug_info( child_info );

		parse_para *child_para;
		child_para = child_info->get_parse_para();
		if( child_para->get_acceptted_count() > 0 &&
			child_para->get_acceptted_syn( child_para->get_acceptted_count()-1 ) != syn )
			syn->debug_info( child_info );

		result = syn->reparse( child_info );
		if( result )
		{
			parse_para *tmp;
			int acceptted;
			tmp = child_info->get_parse_para();
			acceptted = tmp->get_last_start_code() - para->get_code();
			para->remove_last_acceptted();
			result = para->add_acceptted( this, acceptted );
		}
		return result;
	}

	bool syntax_entry::do_parse( parse_para *para, syntax *syn, parse_info *child_info )
	{
		bool result = false;
		
		if( syn == this )
			syn->debug_info( child_info );

		result = syn->parse( child_info );
		if( result )
		{
			parse_para *tmp;
			int acceptted;
			tmp = child_info->get_parse_para();
			acceptted = tmp->get_last_start_code() - para->get_code();
			result = para->add_acceptted( this, acceptted );
		}
		return result;
	}

	bool syntax_entry::can_accept_more( parse_para *para )
	{
		return true;
	}

	bool syntax_entry::should_accept_more( parse_para *para )
	{
		int real = para->get_acceptted_count();
		return real < 1;
	}

}